package com.ncs.nc.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class RabbitmqConfig {
    //定义日志
    private static final Logger log= LoggerFactory.getLogger(RabbitmqConfig.class);

    //自动装配RabbitMQ的链接工厂实例
    @Autowired
    private CachingConnectionFactory ccFactory;

    //自动装配消息监听器所在的容器工厂配置类实例
    @Autowired
    private SimpleRabbitListenerContainerFactoryConfigurer factoryConfigurer;

    //自定义配置RabbitMQ发送消息的操作组件RabbitTemplate
    @Bean
    public RabbitTemplate rabbitTemplate(){
        //设置“发送消息后进行确认”
        ccFactory.setPublisherConfirms(true);
        //设置“发送消息后返回确认信息”
        ccFactory.setPublisherReturns(true);
        //构造发送消息组件实例对象
        RabbitTemplate rabbitTemplate=new RabbitTemplate(ccFactory);

        //mandatory取值为true时，消息通过交换器无法匹配到队列会返回给生产者
        //取值为false时，匹配不到的消息会直接被丢弃
        rabbitTemplate.setMandatory(true);

        //发送消息后，如果发送成功，则输出“消息发送成功”的反馈消息
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                log.info("消息发送成功：:correlation({}),ack({}),cause({})",correlationData,ack,cause);
            }
        });

        //发送消息后，如果发送失败，则输出“消息发送失败-消息丢失”的反馈信息
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                log.info("消息丢失:exchange({}),rout({}),replyCode({}),replyText({}),message:{}",exchange,routingKey,replyCode,replyText,message);
            }
        });

        //最终返回RabbitMQ的操作组件实例RabbitTemplate
        return rabbitTemplate;
    }

    //环境实例注入？？？
    @Autowired
    private Environment env;

    //创建简单的消息模型
    @Bean
    public Queue simpleQueue(){
        //设定持久化，非自动删除
//        Queue queue=new Queue(env.getProperty("mq.simple.queue"),true,false,false);
        Queue queue=new Queue("local.mq.simple.queue",true,false,false);
        return queue;
    }
    @Bean
    public DirectExchange simpleExchange(){
        //设定持久化，非自动删除
        return new DirectExchange("local.mq.simple.exchange",true,false);
    }

    //交换机+路由键 --> 绑定路由到队列
    @Bean
    public Binding simpleBind(){
        return BindingBuilder.bind(simpleQueue()).to(simpleExchange()).with("");
    }


    /**
     * 基于FanoutExchange的消息模型
     */
//  创建交换器 - fanoutExchange
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange(env.getProperty("mq.fanout.exchange.name"),true,false);
    }
//  创建队列1
    @Bean
    public Queue fQueueA(){
        return new Queue(env.getProperty("mq.fanout.queue.a.name"),true);
    }
//  创建队列2
    @Bean
    public Queue fQueueB(){
        return new Queue(env.getProperty("mq.fanout.queue.b.name"),true);
    }
//  创建绑定1
    @Bean
    public Binding fanoutBindingOne(){
        return BindingBuilder.bind(fQueueA()).to(fanoutExchange());
    }
//  创建绑定2
    @Bean
    public Binding fanoutBindingTwo(){
        return BindingBuilder.bind(fQueueB()).to(fanoutExchange());
    }


    /**
     * 基于DirectExchange的消息模型
     */
    //创建交换器 - DirectExchange
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange(env.getProperty("mq.direct.exchange.name"),true,false);
    }
    //创建队列
    @Bean
    public Queue directQueueOne(){
        return new Queue(env.getProperty("mq.direct.queue.name"),true);
    }
    //创建绑定
    @Bean
    public Binding directBindingOne(){
        return BindingBuilder.bind(directQueueOne()).to(directExchange()).with(env.getProperty("mq.direct.routing.key.name"));
    }


    /**
     * 基于TopicExchange交换器的消息模型
     */
    //创建队列
    @Bean
    public Queue topicQueue(){
        return new Queue(env.getProperty("mq.topic.queue.name"),true);
    }
    //创建交换器 - DirectExchange?
    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange(env.getProperty("mq.topic.exchange.name"),true,false);
    }
    //创建绑定
    @Bean
    public Binding topicBindOne(){
        return BindingBuilder.bind(topicQueue())
                .to(topicExchange())
                .with(env.getProperty("mq.topic.routing.key.name"));
    }


    /**
     *
     * RabbitMQ死信队列消息模型实战
     *
     * */
    @Bean
    public Queue deadQueue(){
        //创建死信队列的组成部分map, 用于存放组成成分的相关成员
        Map<String, Object> argMap= new HashMap<>();
        //创建死信交换器
        argMap.put("x-dead-letter-exchange",env.getProperty("mq.dead.exchange.name"));
        //创建死信路由键
        argMap.put("x-dead-letter-routing-key",env.getProperty("mq.dead.routing.key.name"));
        //设定ttl，单位为ms
        argMap.put("x-message-ttl",8000);
        //创建并返回死信队列实例
        return new Queue(env.getProperty("mq.dead.queue.name"),true,false,false,argMap);
    }
    //创建“基本消费模型”的基本交换器-面向生产者
    @Bean
    public DirectExchange basicExchange(){
        return new DirectExchange(env.getProperty("mq.dead.prod.exchange"),true,false);
    }
    //创建“基本消费模型”的基本绑定-基本交换器+基本路由键-面向生产者
    @Bean
    public Binding basicBinding(){
        return BindingBuilder.bind(deadQueue()).to(basicExchange()).with(env.getProperty("mq.dead.prod.routing.key.name"));
    }
    //创建真正队列-面向消费者
    @Bean
    public Queue realQueue(){
        return new Queue(env.getProperty("mq.dead.prod.queue.name"),true);
    }
    //创建死信交换器
    @Bean
    public DirectExchange deadExchange(){
        return new DirectExchange(env.getProperty("mq.dead.exchange.name"),true,false);
    }
    //创建死信路由键及其绑定
    @Bean
    public Binding deadBinding(){
        return BindingBuilder.bind(realQueue()).to(deadExchange()).with(env.getProperty("mq.dead.routing.key.name"));
    }

    /**
     * RabbitMQ延迟队列
     */
    @Bean
    public Queue delayQueue(){
        return QueueBuilder.durable(env.getProperty("mq.delay.queue")).build();
    }
    @Bean
    public CustomExchange delayExchange(){
        Map<String,Object> map=new HashMap<>();
        //设置延迟交换器类型:direct
        map.put("x-delayed-type","direct");
        //自定义交换器，指定其具有延迟的特性
        return new CustomExchange(env.getProperty("mq.delay.exchange"),"x-delayed-message",true,false,map);
    }
    @Bean
    public Binding delayBinding(){
        return BindingBuilder.bind(delayQueue()).to(delayExchange()).with(env.getProperty("mq.delay.routing.key")).noargs();
    }

}
